package com.zxb.base.autoform.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.zxb.base.autoform.enm.LayoutTypeEnum;
import com.zxb.core.common.A;
import com.zxb.core.common.C;
import com.zxb.core.common.R;
import com.zxb.core.dao.autoform.*;
import com.zxb.core.util.JsonUtil;
import com.zxb.base.autoform.util.TableUtil;
import com.zxb.core.common.Req;
import lombok.RequiredArgsConstructor;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author Zxb
 */
@RestController
@RequiredArgsConstructor
public class FormController {
    private final DiyFormDao formDao;
    private final DiyColumnDao columnDao;
    private final DiyFormulaDao formulaDao;
    private final DiyLayoutDao layoutDao;
    private final DiyHeaderDao headerDao;
    private final DiyConditionDao conditionDao;
    private final JdbcTemplate jdbcTemplate;
    private final TableUtil tableUtils;

    @PostMapping("/form/add")
    public R add(@RequestBody DiyForm obj) {
        if (formDao.exists(
                new QueryWrapper<DiyForm>()
                        .lambda()
                        .eq(DiyForm::getName, obj.getName())
        )) {
            return R.error("表单名称已经存在");
        }
        if (formDao.exists(
                new QueryWrapper<DiyForm>()
                        .lambda()
                        .eq(DiyForm::getCode, obj.getCode())
        )) {
            return R.error("表单编码已经存在");
        }
        obj.setSearchStr(obj.getName() + obj.getCode());
        ObjectNode on = JsonUtil.on();
        on.put("视图边距", "10");
        on.put("标签宽度", "120");
        on.put("标签对齐", "right");
        on.put("左右间距", "10");
        on.put("上下间距", "10");
        String defaultLayout = on.toString();
        obj.setAddLayout(defaultLayout);
        obj.setUpdateLayout(defaultLayout);
        obj.setBatchLayout(defaultLayout);
        //默认一个流程实例只对应一条数据
        obj.setDataLimit(1);
        formDao.save(obj);
        //生成表结构
        tableUtils.createTable(obj.getCode());
        return R.success();
    }

    @PostMapping("/form/update")
    public R update(@RequestBody DiyForm obj) {
        DiyForm old = formDao.getById(obj.getId());
        A.isInDatabase(old, "表单");
        //缓存旧编码
        String oldCode = old.getCode();
        if (formDao.exists(
                new QueryWrapper<DiyForm>()
                        .lambda()
                        .eq(DiyForm::getName, obj.getName())
                        .ne(DiyForm::getId, obj.getId())
        )) {
            return R.error("表单名称已经存在");
        }
        BeanUtil.copyProperties(obj, old, C.IGNORED_PROPERTIES);
        old.setSearchStr(obj.getName() + obj.getCode());
        //恢复旧编码
        old.setCode(oldCode);
        formDao.updateById(old);
        return R.success();
    }

    @PostMapping("/form/del")
    public R del(@RequestBody List<Long> ids) {
        formDao.removeBatchByIds(ids);
        return R.success();
    }

    private ObjectNode generateColumnOn(DiyLayout t, List<DiyColumn> columnList) {
        ObjectNode on = JsonUtil.on();
        Long columnId = t.getColumnId();
        on.put("id", String.valueOf(columnId));
        on.put("span", t.getSpan());
        on.put("offset", t.getOffset());
        on.put("sort", t.getSort());
        on.put("isExist", false);
        DiyColumn column = columnList.stream()
                .filter(c -> c.getId().equals(columnId))
                .findFirst().orElse(null);
        if (column != null) {
            on.put("isExist", true);
            on.put("isNeed", column.getIsNeed());
            on.put("isHide", column.getIsHide());
            on.put("isCal", column.getIsCal());
            on.put("name", column.getName());
            on.put("code", column.getCode());
            on.put("type", column.getCompType());
            on.put("extra", column.getExtra());
            on.put("defaultVal", column.getDefaultVal());
            on.put("regex", column.getRegex());
            on.put("errorMsg", column.getErrorMsg());
        }
        return on;
    }

    public Map<String, Object> generateFormInfo(DiyForm obj) {
        //获取公式
        List<DiyFormula> formulaList = formulaDao.list(new QueryWrapper<DiyFormula>()
                .lambda().eq(DiyFormula::getFormId, obj.getId()));
        //获取全部字段
        List<DiyColumn> columnList = columnDao.list(new QueryWrapper<DiyColumn>()
                .lambda().eq(DiyColumn::getFormId, obj.getId()));
        //获取全部字段ID
        List<Long> columnIdList = columnList.stream()
                .map(t -> t.getId())
                .collect(Collectors.toList());
        //获取所有布局
        List<DiyLayout> layoutList = layoutDao.list(new QueryWrapper<DiyLayout>()
                .lambda()
                .in(DiyLayout::getColumnId, columnIdList));
        //获取新增布局字段
        List<ObjectNode> addColumnList = layoutList.stream()
                .filter(x -> obj.getId().equals(x.getFormId()) && LayoutTypeEnum.add.name().equals(x.getType()))
                .map(t -> generateColumnOn(t, columnList))
                .collect(Collectors.toList());
        //获取更新布局字段
        List<ObjectNode> updateColumnList = layoutList.stream()
                .filter(x -> obj.getId().equals(x.getFormId()) && LayoutTypeEnum.update.name().equals(x.getType()))
                .map(t -> generateColumnOn(t, columnList))
                .collect(Collectors.toList());
        //获取批量更新布局字段
        List<ObjectNode> batchColumnList = layoutList.stream()
                .filter(x -> obj.getId().equals(x.getFormId()) && LayoutTypeEnum.batch.name().equals(x.getType()))
                .map(t -> generateColumnOn(t, columnList))
                .collect(Collectors.toList());
        //获取表头设置
        List<DiyHeader> headerList = headerDao.list(new QueryWrapper<DiyHeader>()
                .lambda()
                .eq(DiyHeader::getFormId, obj.getId())
                .eq(DiyHeader::getUsername, Req.getCurrUser().getUsername()));
        //是否设置了查询视图
        Boolean hasFilter = conditionDao.exists(new QueryWrapper<DiyCondition>()
                .lambda()
                .eq(DiyCondition::getFormId, obj.getId()));
        Map<String, Object> map = new LinkedHashMap<>();
        map.put("id", obj.getId());
        map.put("name", obj.getName());
        map.put("code", obj.getCode());
        map.put("addLayout", obj.getAddLayout());
        map.put("updateLayout", obj.getUpdateLayout());
        map.put("batchLayout", obj.getBatchLayout());
        map.put("validUrl", obj.getValidUrl());
        map.put("hasAttach", obj.getHasAttach());
        map.put("attType", obj.getAttType());
        map.put("dataLimit", obj.getDataLimit());
        map.put("needForm", obj.getNeedForm());
        map.put("needStep", obj.getNeedStep());
        map.put("formulas", formulaList);
        map.put("allColumns", columnList);
        map.put("addColumns", addColumnList);
        map.put("updateColumns", updateColumnList);
        map.put("batchColumns", batchColumnList);
        map.put("headers", headerList);
        map.put("hasFilter", hasFilter);
        return map;
    }

    @GetMapping("/form/oneByCode")
    public R findOneByCode(String code) {
        DiyForm obj = formDao.getOne(new QueryWrapper<DiyForm>()
                .lambda().eq(DiyForm::getCode, code));
        A.isInDatabase(obj, "表单");
        return R.success(generateFormInfo(obj));
    }

    @GetMapping("/form/oneById")
    public R findOneById(Long formId) {
        DiyForm obj = formDao.getById(formId);
        A.isInDatabase(obj, "表单");
        return R.success(generateFormInfo(obj));
    }

    @GetMapping("/form/list")
    public R list() {
        List<DiyForm> list = formDao.list();
        return R.success(list);
    }

    @GetMapping("/form/page")
    public R page(String searchStr, Integer page, Integer pageSize) {
        IPage<DiyForm> pageParam = new Page<>(page, pageSize);
        QueryWrapper<DiyForm> queryWrapper = new QueryWrapper<>();
        if (StrUtil.isNotBlank(searchStr)) {
            queryWrapper.lambda().like(DiyForm::getSearchStr, "%" + searchStr + "%");
        }
        IPage<DiyForm> result = formDao.page(pageParam, queryWrapper);
        return R.success(result);
    }

    @GetMapping("/form/create/table")
    public R page(String id) {
        DiyForm settleForm = formDao.getById(Long.valueOf(id));
        int i = tableUtils.createTable(settleForm.getCode());
        if (i < 0) {
            return R.error(String.valueOf(i));
        }
        return R.success();
    }

    @PostMapping("/form/layout/update")
    public R updateLayout(@RequestBody Map<String, Object> map) {
        Long formId = Long.valueOf((String) map.get("formId"));
        DiyForm old = formDao.getById(formId);
        A.isInDatabase(old, "表单");
        String type = (String) map.get("type");
        String layout = (String) map.get("layout");
        if (StrUtil.isBlank(type)) {
            return R.error("布局类型为空");
        }
        if (StrUtil.isBlank(layout)) {
            return R.error("布局json数据为空");
        }
        if (LayoutTypeEnum.add.name().equals(type)) {
            old.setAddLayout(layout);
        } else if (LayoutTypeEnum.update.name().equals(type)) {
            old.setUpdateLayout(layout);
        } else if (LayoutTypeEnum.batch.name().equals(type)) {
            old.setBatchLayout(layout);
        }
        formDao.updateById(old);
        return R.success();
    }
}
